
package Indexador;

import AlmacenTemp.AlmacenTemp;
import AlmacenTemp.PagTemp;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * Indexador secundario, encargado de leer HTML, extraer los temas y almacenarlos
 * en la BD de temas.
 * @see TemasBD
 *
 * @author Mikel&Igor
 */
public class IndexadorWorker extends Thread
{
    //Página procesada
    private PagTemp pagina;
    /**
     * Segundos de espera si no hay páginas en el almacén temporal
     */
    public int segundosEspera;

    /**
     * Constructor por defecto. El tiempo de espera por defecto
     * será de 2 segundos.
     */
    public IndexadorWorker()
    {
        segundosEspera=2;
    }

    /**
     * Constructor. Crea un worker.
     *
     * @param segundosEspera El número de segundos que esperará antes de
     * intentar coger una página si no hay páginas en el almacén.
     */
    public IndexadorWorker(int segundosEspera)
    {
        this.segundosEspera = segundosEspera;
    }

    /**
     * Getter. Devuelve los segundos que hay que esperar entre dos peticiones
     * de página si no hay ninguna en la primera petición.
     *
     * @return El número de segundos.
     */
    public int getSegundosEspera()
    {
        return segundosEspera;
    }

    /**
     * Setter. Configura los segundos que hay que esperar entre dos peticiones
     * de página si no hay ninguna en la primera petición.
     *
     * @param segundosEspera El número de segundos.
     */
    public void setSegundosEspera(int segundosEspera) {
        this.segundosEspera = segundosEspera;
    }

    /**
     * Poner el worker a indexar
     */
    @Override
    public void run()
    {
        //Mantendremos el hilo en ejecución hasta que se pare el indexador principal
        while(true)
        {
            procesarSiguiente();
        }
    }

    /**
     * Procesa la siguiente página temporal
     */
    private void procesarSiguiente()
    {
        //Cogemos la siguiente página temporal
        pagina=AlmacenTemp.sacar();

        if(pagina==null) //Si no hay una página, esperamos
        {
            try
            {
                sleep(1000*segundosEspera);
            }
            catch(InterruptedException ex)
            {
                //No hacemos nada
            }
        }

        else
        {
            procesarPagina();
        }
    }

    /**
     * Procesa la página temporal almacenada, dependiendo de la URL desde la que
     * fue obtenida.
     */
    private void procesarPagina()
    {
        /* Si es una página obtenida desde www.vagos.es pasamos a ese procesador
         * en concreto. */
        System.out.println(pagina.getURL());

        if(pagina.getURL().contains("www.vagos.es"))
            procesarPaginaVagos();
    }

    /**
     * Procesa un HTML obtenido en www.vagos.es, obteniendo un Tema asociado
     * a la URL desde la que lo obtuvimos.
     */
    private void procesarPaginaVagos()
    {
        String URL; //URL de la página
        String tituloCompleto=""; //Título completo del tema
        GrupoDescargas gd=null; //Último grupo de descargas obtenido.
        Tema tema; //Tema obtenido
        StringTokenizer tok;
        String nextToken;
        Pattern titlePatt;
        Matcher titleMat;
        String textoPlano,ultimoTexto="",ultimoCap="";
        ComparadorLinks comparador=new ComparadorLinks();

        URL= pagina.getURL();

        tok=new StringTokenizer(pagina.getHTML(),"\n");

        
        nextToken=tok.nextToken();

        /* Buscamos el título del tema. Para encontrarlo, sabemos que utilizan
         * siempre el tag <!-- icon and title -->, y el título está entre
         * <strong> y </strong>.Hacemos una búsqueda por el HTML para
         * encontrar el tag. */
        while(tok.hasMoreTokens() && !nextToken.contains("<!-- icon and title -->"))
             nextToken=tok.nextToken();

        /* Ahora buscamos la línea correspondiente al título. Por seguridad nos
         * aseguramos de que ha encontrado un título. En algunos post no existe
         * éste y, ya que no tiene un título acorde con las normas, será
         * borrado. Por tanto, no lo procesamos. Para encontrarlo y separar
         * la parte útil, utilizamos una expresión regular. */
        
        titlePatt=Pattern.compile("(^\t*)(<strong>)(.*)( -.*)");
        titleMat=titlePatt.matcher(nextToken);

        while(tok.hasMoreTokens() && !titleMat.find() && !nextToken.contains("<!-- / icon and title -->"))
        {
             nextToken=tok.nextToken();
             titleMat=titlePatt.matcher(nextToken);
        }

        //Si no es válido, lo eliminamos
        if(nextToken.contains("<!-- / icon and title -->"))
            return;
        else if(tok.hasMoreTokens()) //Si no ha salido por algún error en el HTML
            tituloCompleto = titleMat.group(3); //Almacenamos el título

        tema=new Tema(tituloCompleto, URL);

        /* Cada tema tiene varios Post (uno por cada comentario). Nos interesará
         * sólo el primero de los comentarios. Para identificar los mensajes usan
         * el tag comentado <!-- message --> Por tanto, haremos una búsqueda por
         * el HTML hasta encontrarlo */
         while(tok.hasMoreTokens() && !nextToken.contains("<!-- message -->"))
             nextToken=tok.nextToken();

        nextToken=tok.nextToken();

        /* Una vez encontrado el inicio del mensaje lo recorreremos hasta el
         * final. Identificaremos el final con el tag <!-- / message --> */
         while(tok.hasMoreTokens() && !nextToken.contains("<!-- / message -->"))
         {
             nextToken=tok.nextToken();

             //Si encontramos un "cajón" de enlaces. Es un <pre> de clase alt2
             if(nextToken.contains("<pre class=\"alt2\""))
             {
                 String link;

                 /* Creamos el grupo de descargas. Como identificador usaremos
                  * el último capítulo leido si existe y si no el último texto
                  * plano leído. */
                 String identificador=ultimoCap;
                 if(identificador.equals(""))
                     identificador=ultimoTexto;
                 //Borramos el último capítulo para que no se reutilice
                 ultimoCap="";

                 gd=new GrupoDescargas(identificador);

                 //Mientras no lleguemos al final del "cajon"
                 while(tok.hasMoreTokens() && !nextToken.contains("</pre>"))
                 {
                     //Si es un link válido lo añadimos
                    if((link=comparador.getURLFromText(nextToken))!=null)
                        gd.addENlace(link);

                     nextToken=tok.nextToken();
                 }

                 //El último tema también podía contener algún enlace
                 //Si es un link válido lo añadimos
                    if((link=comparador.getURLFromText(nextToken))!=null)
                        gd.addENlace(link);

                 if(!gd.getListaEnlaces().isEmpty())
                    tema.addGd(gd);
             }

             //Si encontramos un spoiler
             else if(nextToken.contains("<div id=\"spoiler\">"))
             {
                 String link;
                 
                 /* Creamos el grupo de descargas. Como identificador usaremos
                  * el último capítulo leido si existe y si no el último texto
                  * plano leído. */
                 String identificador=ultimoCap;
                 if(identificador.equals(""))
                     identificador=ultimoTexto;
                 //Borramos el último capítulo para que no se reutilice
                 ultimoCap="";

                 gd=new GrupoDescargas(identificador);
                //Mientras no encontremos elfinal
                 while(tok.hasMoreTokens() && !nextToken.contains("</pre>"))
                 {
                     //Si es un link válido lo añadimos
                    if((link=comparador.getURLFromText(nextToken))!=null)
                        gd.addENlace(link);

                     nextToken=tok.nextToken();
                 }

                 if(tok.hasMoreTokens() && nextToken.contains("</pre>"))
                     nextToken=tok.nextToken();
             }

             //Si encontramos un enlace válido
             else if(comparador.comparaLinks(nextToken))
             {
                 boolean saltoLeido=false;
                 String link=comparador.getURLFromText(nextToken);

                 /* Creamos el grupo de descargas. Como identificador usaremos
                  * el último capítulo leido si existe y si no el último texto
                  * plano leído. */

                 String identificador=ultimoCap;
                 if(identificador.equals("")) //Si no hay título
                 {
                     //Comprobamos si hay algo en la misma línea
                     String aux=leerTextoPlano(nextToken);

                     //Si no contiene el enlace se lo asignamos
                     if(!comparador.comparaLinks(aux))
                        identificador=leerTextoPlano(nextToken);
                     else
                         identificador=ultimoTexto;
                 }
                 //Borramos el último capítulo para que no se reutilice
                 ultimoCap="";

                 gd=new GrupoDescargas(identificador);
                 gd.addENlace(link);

                 if(nextToken.contains("<br>"))
                     saltoLeido=true;

                 /* Mientras no se acabe el HTML y no haya más de un salto de
                  * línea entre un enlace y otro, seguimos almacenando enlaces. */
                 while(tok.hasMoreTokens() && !nextToken.contains("<br><br>"))
                 {
                     nextToken=tok.nextToken();

                     //Si es un salto de línea
                     if(nextToken.equals("<br>"))
                         if(saltoLeido)
                             break;
                         else if(nextToken.equals("<br><br>"))
                             break;
                         else
                             saltoLeido=true;

                     else //Si no lo es
                         if((link=comparador.getURLFromText(nextToken))!=null) //Si es un link lo almacenamos
                         {
                                gd.addENlace(link);
                                
                                if(!nextToken.contains("<br>"))
                                    saltoLeido=false;
                                if(nextToken.contains("<br><br>"))
                                    break;
                        }

                 }
                 if(!gd.getListaEnlaces().isEmpty())
                    tema.addGd(gd);
             }

             /* Almacenaremos el texto plano para usarlo como título en los
              * grupos de descarga */
             textoPlano=leerTextoPlano(nextToken);

             if(!textoPlano.equals(""))
             {
                 ultimoTexto=textoPlano;

                 /* Almacenaremos los nombres de capítulos si los hay. Para
                  * saber si existe un título de capítulo, compararemos con
                  * el texto capítulo. Para ello lo ponemos en minúsculas y sin
                  * acentos. */
                 String aux=FuncionesTexto.minusculaSinAcento(textoPlano);

                 if(((aux.contains("cap.") || aux.contains("capitulo")) && !aux.contains("capitulos")) ||
                         (aux.contains("ep.") || aux.contains("episodio")) && !aux.contains("episodios"))
                 {
                     ultimoCap=textoPlano;
                 }
             }
         }

        //Almacenamos el tema
        if(tema!=null)
        {
            TemasBD.guardarTema(tema);
        }
    }

    private String leerTextoPlano(String texto)
    {
        Pattern pat=Pattern.compile("(\t)*(<[^<>]*>){0,}([^<>]*)");
        Matcher mat=pat.matcher(texto);
        String textoPlano="";

        while(mat.find())
            textoPlano+=mat.group(3);

        if(textoPlano!=null)
        {
            if(textoPlano.equals("Código:"))
                return "";
            else
                return textoPlano;
        }
        else
            return "";
    }
}
